/**
 *
 */
package com.cmcc.xdr.pcapparse.tcp.https;

import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.cmcc.pcap.jpcap.tcp.TcpPacketDecorator;
import org.cmcc.pcap.jpcap.tcp.http.HttpTransaction;

import com.cmcc.xdr.entity.HttpEntity;
import com.cmcc.xdr.pcapparse.tcp.http.HttpProtoDistinguishStatistics;
import com.cmcc.xdr.util.DateUtil;
import com.cmcc.awareness.AppInfo;
import com.cmcc.awareness.HttpProto;


/**
 * @Date 2018年3月21日 下午6:48:11
 * @author Amish
 *
 */
public class HttpsXdrGenerate {
	private static Logger logger = LogManager.getLogger(HttpsXdrGenerate.class);
	
	public  ArrayList<HttpEntity> httpsEntityList = new ArrayList<HttpEntity>();
	
	public void generate(HttpTransaction httpsTransaction) {
		//TcpConnection tcpConnection = httpTransaction.tcpConnection;
		HttpEntity httpsEntity = new HttpEntity();
		
		StringBuilder server_name = null;
		Iterator<TcpPacketDecorator> i = httpsTransaction.al_splited.iterator();
		while(i.hasNext()){
			TcpPacketDecorator tpd = (TcpPacketDecorator) i.next();
			if(tpd.getData(1).length > 0){
				//获取 server name
				StringBuilder server_name_temp = findHttpsClientHelloInfo(tpd);
				if(server_name_temp != null){
					server_name = server_name_temp;
					break;
				}
			}
		}
		String server_name_final = ""+server_name;
		logger.debug("server name is: "+server_name_final);
		
		
		String id_at_commonName = null;
		Iterator<TcpPacketDecorator> j = httpsTransaction.al_splited.iterator();
		while(j.hasNext()){
			TcpPacketDecorator tpd = (TcpPacketDecorator) j.next();
			if(tpd.getData(1).length > 0){
				//获取 server name
				String id_at_commonName_temp = findHttpsCertificateInfo(tpd);
				if(id_at_commonName_temp != null && id_at_commonName_temp.length()>0){
					id_at_commonName = id_at_commonName_temp;
					break;
				}
			}
		}
		String id_at_commonName_final = id_at_commonName;
		logger.debug("id at commonName is: "+id_at_commonName_final);

		
		HttpProto httpproto = HttpProto.getInstance();
		AppInfo appInfo = httpproto.appDistinguish(server_name_final, id_at_commonName_final);
		if(appInfo!=null){
			HttpProtoDistinguishStatistics.getInstance().incrementDistinguish(appInfo);
			logger.debug("\n[ match app rule ]"+appInfo.toString());

			//填写APP_type
			String appType = appInfo.getNum_type();
			httpsEntity.setAppType(appType);
			
			//填写APP_SUB_type
			String appSubType = appInfo.getNum_subtype();
			httpsEntity.setAppSubType(appSubType);
			
		}else{
			HttpProtoDistinguishStatistics.getInstance().incrementUnDistinguish();
			logger.debug("\n[ do not match any app rule ]");
		}
		
	
		try {
			saveHttpsTcpConnectionToHttpsEntityList(httpsTransaction,httpsEntity);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			logger.error(e.getCause(), e);
		}
		
		//将每个httpEntity加入httpEntityList中，调用SaveHttpTransactionInfo的save方法保存到数据库中
		httpsEntityList.add(httpsEntity);
		
		/**
		 * Interface
		 * ProcedureStartTime
		 * ProcedureEndTime
		 * ProtocolType
		 * AppType
		 * AppSubType
		 * IPAddressType
		 * UserIPv4
		 * UserIPv6
		 * ......
		 * 
		 * UL Data上行流量
		 * DL Data下行流量
		 * UL IP Packet上行IP包数
		 * DL IP Packet下行IP包数
		 * UL Disorder IP Packet上行TCP乱序报文数
		 * DL Disorder IP Packet下行TCP乱序报文数
		 * UL Retrans IP Packet上行TCP重传报文数
		 * DL Retrans IP Packet下行TCP重传报文数
		 * UL_IP_FRAG_PACKETS上行IP包的分片数
		 * DL_IP_FRAG_PACKETS下行IP包的分片数
		 * TCP SYN Num：TCP SYN次数
		 * TCP SYN ACK Num：TCP SYN ACK的次数
		 * TCP ACK Num：回复SYN ACK的ACK次数
		 * 
		 * 
		 */
			
	}
	
	public void saveHttpsTcpConnectionToHttpsEntityList(HttpTransaction httpsTransaction,HttpEntity httpsEntity) throws ParseException{
		
		//填写IE和PORTAL,默认值是0，必须填写
		httpsEntity.setIe(0);
		httpsEntity.setPortal(0);
		
		Integer length = httpsTransaction.al_splited.size();
		logger.debug("tcpConnection length:"+length);
		
		TcpPacketDecorator tpdStart = httpsTransaction.al_splited.get(0);
		TcpPacketDecorator tpdEnd = httpsTransaction.al_splited.get(length-1);		
		
		//计算procedure_start_time
		long timestamp_procedure_start_time = tpdStart.tcpPacket.sec*1000 + tpdStart.tcpPacket.usec;
		Date procedureStartTime = DateUtil.formatTimestamp(timestamp_procedure_start_time);
		httpsEntity.setProcedureStartTime(procedureStartTime);
				
		//计算procedure_end_time
		long timestamp_procedure_end_time = tpdEnd.tcpPacket.sec*1000 + tpdEnd.tcpPacket.usec;
		Date procedureEndTime = DateUtil.formatTimestamp(timestamp_procedure_end_time);
		httpsEntity.setProcedureEndTime(procedureEndTime);
		
		//填写interface
		Integer interFace = 11;
		httpsEntity.setInterFace(interFace);
		
		//填写ip_address_type,ipv4是0,ipv6是1
		httpsEntity.setIpAddressType(0);
				
		//填写终端用户的ipv4地址
		String userIpv4 = tpdStart.tcpPacket.src_ip.toString();
		userIpv4 = userIpv4.replace("/", "");
		httpsEntity.setUserIpv4(userIpv4);
				
		//填写终端用户ipv6地址
		String userIpv6 = "1111111111111111";
		httpsEntity.setUserIpv6(userIpv6);
					
		//填写终端用户port
		Integer userPort = tpdStart.tcpPacket.src_port;
		httpsEntity.setUserPort(userPort);
					
		//填写L4 Protocol,0为tcp,1为udp
		httpsEntity.setL4Protocal(0);
		
		//填写服务端ipv4地址
		String appServerIpIpv4 = tpdStart.tcpPacket.dst_ip.toString();
		appServerIpIpv4 = appServerIpIpv4.replace("/", "");
		httpsEntity.setAppServerIpIpv4(appServerIpIpv4);
					
		//填写服务端ipv6地址
		String appServerIpIpv6 = "1111111111111111";
		httpsEntity.setAppServerIpIpv6(appServerIpIpv6);
					
		//填写服务端port
		Integer appServerPort = tpdStart.tcpPacket.dst_port;
		httpsEntity.setAppServerPort(appServerPort);
		
		//填写上行流量DL DATA
		Integer ulData = httpsTransaction.UL_Data;
		httpsEntity.setUlData(ulData);
				
		//填写下行流量UL DATA
		Integer dlData = httpsTransaction.DL_Data;
		httpsEntity.setDlData(dlData);
				
		//填写上行ip包个数 
		Integer ulIpPacket = httpsTransaction.UL_IP_Packet;
		httpsEntity.setUlIpPacket(ulIpPacket);
				
		//填写下行ip包葛素
		Integer dlIpPacket = httpsTransaction.DL_IP_Packet;
		httpsEntity.setDlIpPacket(dlIpPacket);
				
		//填写上行tcp乱序包
		Integer ulDisorderIpPacket = httpsTransaction.UL_Disorder_IP_Packet;
		httpsEntity.setUlDisorderIpPacket(ulDisorderIpPacket);
				
		//填写下行tcp乱序包
		Integer dlDisorderIpPacket = httpsTransaction.DL_Disorder_IP_Packet;
		httpsEntity.setDlDisorderIpPacket(dlDisorderIpPacket);
				
		//填写上行tcp重传包
		Integer ulRetransIpPacket = httpsTransaction.UL_Retrans_IP_Packet;
		httpsEntity.setUlRetransIpPacket(ulRetransIpPacket);
				
		//填写下行tcp重传包
		Integer dlRetransIpPacket = httpsTransaction.DL_Retrans_IP_Packet;
		httpsEntity.setDlRetransIpPacket(dlRetransIpPacket);
				
		//填写上行ip分片数
		Integer ulIpFragPackets = httpsTransaction.UL_IP_FRAG_PACKETS;
		httpsEntity.setUlIpFragPackets(ulIpFragPackets);
				
		//填写下行ip分片数
		Integer dlIpFragPackets = httpsTransaction.DL_IP_FRAG_PACKETS;
		httpsEntity.setDlIpFragPackets(dlIpFragPackets);
				
		//填写tcp中syn的次数
		Integer tcpSynNum = httpsTransaction.TCP_SYN_Num;
		httpsEntity.setTcpSynNum(tcpSynNum);
				
		//填写tcp中syn ack次数
		Integer tcpSynAckNum = httpsTransaction.TCP_SYN_ACK_Num;
		httpsEntity.setTcpSynAckNum(tcpSynAckNum);
				
		//填写回复syn ack的ack次数
		Integer tcpAckNum = httpsTransaction.TCP_ACK_Num;
		httpsEntity.setTcpAckNum(tcpAckNum);
		
		//填写protocol type，https是2
		httpsEntity.setProtocolType("2");
		
		
//		//获取 server name
//		ArrayList<TcpPacketDecorator> tcpPacketlist = httpsTransaction.al_splited;
//		for(int j=0; j< tcpPacketlist.size(); ++j){
//			TcpPacketDecorator temptpd = tcpPacketlist.get(j);
//			StringBuilder server_name_temp = findHttpsInfo(temptpd);
//			if(server_name_temp != null){
//				server_name = server_name_temp;
//				break;
//			}
//		}
//		logger.debug("server name is: "+server_name);
		
	}
	
	public String findHttpsCertificateInfo(TcpPacketDecorator tcpPacketDecorator){
//
//		byte[] tslhandshake1 = {(byte) 0x16};//记录层握手协议类型标识
//		byte[] tslhandshake2 = {(byte) 0x0b};//上层协议中的握手协议标识,certificate为Ox0b
		
		if(tcpPacketDecorator.tcpPacket.data.length == 0){//该判断多余0613add
			return null;
		}
		
//		byte[] SSLhandshake1 = new byte[1];
//		byte[] SSLhandshake2 = new byte[1];
		byte[] data = tcpPacketDecorator.getData();//TODO https 由于不知道id-at-commonName字段具体会出现在第几个分段，暂时采用获取所有分段。性能问题?
		for (int i = 0; i < data.length-3; i++) {
			if (data[i] == 85 && data[i+1] == 4 && data[i+2] == 3){
				byte[] bytes = new byte[data[i + 4]];
				System.arraycopy(data,i+5, bytes,0, data[i + 4]);
				String idAtCommentName = new String(bytes, Charset.forName("utf-8"));
				boolean matches = Pattern.matches(".*\\.?.*\\..*", idAtCommentName);//TODO 正则匹配?穷举域名后缀?
				if (matches){
					return idAtCommentName;
				}
			}
		}

		return null;

		/*System.arraycopy(data, 0, SSLhandshake1, 0, 1);//记录层握手协议类型为数据部分第1个字节
		System.arraycopy(data, 5, SSLhandshake2, 0, 1);//上层协议的握手协议标识为数据部分的第6个字节
		
		if(Arrays.equals(SSLhandshake1, tslhandshake1) && Arrays.equals(SSLhandshake2, tslhandshake2)){
			logger.info("-------------SSL-----Certificate");
			String dataString = printHexBinary(data);
			dataString.getBytes();
			List<String> list = new ArrayList<>();
			List<String> list1 = new ArrayList<>();
			String str[] = dataString.split(",");
			list = Arrays.asList(str);

		}*/
	}
	
	public StringBuilder findHttpsClientHelloInfo(TcpPacketDecorator tcpPacketDecorator){
		
		byte[] tslhandshake1 = {(byte) 0x16};//记录层握手协议类型标识
		byte[] tslhandshake2 = {(byte) 0x01};//上层协议中的握手协议标识，clienthello为Ox01
		
		if(tcpPacketDecorator.tcpPacket.data.length == 0){//该判断多余0613add
			return null;
		}
		
		/**
		 * ssl协议识别逻辑：
		 * 由于TCP分段的原因，有些基于TCP连接的SSL没有握手阶段，且握手阶段可能存在client发往server的第二条信息由于乱序的原因比第一条client hello更早到达server端，
		 * 而该条信息并不包括server_name字段，所以判断条件取以下三个条件的逻辑“与”：
		 * 		1，端口号为“443”
		 * 		2，判断记录层握手协议类型，即字段content type，该字段为0x16表示为握手协议，为0x17表示为应用数据，也即分段数据
		 * 		3，判断上层协议中的握手协议标识，即字段handshake type，该字段为0x01表示为client hello，为0x02表示为server hello，
		 * 		      相应的有certificate等握手阶段的对应字段值
		 * 0727
		 */
		
		byte[] SSLhandshake1 = new byte[1];
		byte[] SSLhandshake2 = new byte[1];
		byte[] data = tcpPacketDecorator.getData(1);
		System.arraycopy(data, 0, SSLhandshake1, 0, 1);//记录层握手协议类型为数据部分第1个字节
		System.arraycopy(data, 5, SSLhandshake2, 0, 1);//上层协议的握手协议标识为数据部分的第6个字节
		
		if(Arrays.equals(SSLhandshake1, tslhandshake1) && Arrays.equals(SSLhandshake2, tslhandshake2)){
			logger.info("-------------SSL-----Client Hello");
			String dataString = printHexBinary(data);//
			logger.info("-------------data + "+dataString);
			dataString.getBytes();
			List<String> list = new ArrayList<String>();
			List<String> list1 = new ArrayList<String>();
			String str[] = dataString.split(",");
			list = Arrays.asList(str);
			logger.info(list.size());
			
			/**
			 * server_name字段获取
			 * 通过每个字段含义以及长度顺次寻找server_name字段位置
			 * 
			 */
			for (int i = 0; i < list.size(); i++) {
				
				//第44位为session ID length字段，该字段为0时，其下一个字段为Cipher Suites Length
				if(i == 43 && list.get(i) == "00"){
					
					
					i = i + 1;
					
					int lengthCipher = Integer.parseInt((list.get(i)+list.get(i+1)),16);
					i = i + 2 + lengthCipher;//该字段占2字节，故加2
					
					int lengthCompression = Integer.parseInt((list.get(i)),16);
					i = i + 1 + lengthCompression;//该字段占1字节，故加1
					
					//数字9表示字段Compression Methods后到字段server_name length之前的长度，为固定的9字节
					int lengthServerName = Integer.parseInt((list.get(i + 9)+list.get(i + 9 + 1)),16);
					list1.addAll(list.subList(i + 9 + 2, i + 9 + 2 + lengthServerName));//该字段占2字节，故加2
					break;
				}
				//第44位为session ID length字段，该字段不为0时，其下一个字段为session ID
				if(i == 43 && list.get(i) != "00"){
					
					int lengthSession = Integer.parseInt(list.get(i),16);
					i = i + 1 + lengthSession;//该字段占1字节，故加1
					
					int lengthCipher = Integer.parseInt((list.get(i)+list.get(i+1)),16);
					i = i + 2 + lengthCipher;//该字段占2字节，故加2
					
					int lengthCompression = Integer.parseInt((list.get(i)),16);
					i = i + 1 + lengthCompression;//该字段占1字节，故加1
					
					//数字9表示字段Compression Methods后到字段server_name length之前的长度，为固定的9字节
					int lengthServerName = Integer.parseInt((list.get(i + 9)+list.get(i + 9 + 1)),16);
					list1.addAll(list.subList(i + 9 + 2, i + 9 + 2 + lengthServerName));//该字段占2字节，故加2
					break;
					
				}	
			}
			
			logger.info(list1);
			
			//将该字段解析
			StringBuilder sb = new StringBuilder();
			for(int i = 0; i < list1.size(); i++){
				int decimal = Integer.parseInt(list1.get(i), 16);
				sb.append((char) decimal);
			}
			sb.toString();
			logger.info(sb);
			
			//logger.info("-------------ascii + "+convertHexToString(printHexBinary(data)));
			return sb;
		}
		
		return null;

	}
	
    public static String printHexBinary(byte[] data) {
    	char[] hexCode = "0123456789ABCDEF".toCharArray();
        StringBuilder r = new StringBuilder(data.length * 2);
        for (byte b : data) {
            r.append(hexCode[(b >> 4) & 0xF]);
            r.append(hexCode[(b & 0xF)]);
            r.append(",");
        }
        return r.toString();
    }

}
